#pragma once

#include <string>
#include <memory>
#include <vector>

class Component;
typedef std::shared_ptr<Component> ComponentPtr;

class Command;
typedef std::shared_ptr<Command> CommandPtr;

class GameObject
{
public:
	GameObject(const std::string &name, const std::string &description, const std::string &indefinite_article = "a");
	virtual ~GameObject();

    virtual bool is(const std::string &name);

	const std::string &getName() const { return name; }
	virtual std::string getIndefiniteArticle() { return indefinite_article; }
	const std::string &getDescription() const { return description; }

	int getWeight() const { return weight; }

	virtual void look(); //Optional
	virtual void examine(); //Optional
	virtual void update(unsigned int tick); //Optional

	void add(ComponentPtr component);
	template<class ComponentType> std::shared_ptr<ComponentType> add(std::shared_ptr<ComponentType> component);
	void remove(const ComponentPtr &component);
	const std::vector<ComponentPtr> &getComponents() const { return components; }
	template<class ComponentType> std::shared_ptr<ComponentType> getComponent(const std::string &name) const;
	bool hasComponent(const std::string &name) const;
	virtual bool canHandleCommand(const CommandPtr &command);

protected:
	std::string name;
	std::string indefinite_article;
	std::string description;
	unsigned int weight;
	std::vector<ComponentPtr> components;
};
typedef std::shared_ptr<GameObject> GameObjectPtr;

template<class ComponentType>
inline std::shared_ptr<ComponentType> GameObject::add(std::shared_ptr<ComponentType> component)
{
	components.push_back(component);
	return component;
}

template<class ComponentType>
inline std::shared_ptr<ComponentType> GameObject::getComponent(const std::string &name) const
{
	for(unsigned int i = 0; i < components.size(); i++)
	{
		if(components[i]->getName() == name)
		{
#ifdef _DEBUG
			return std::dynamic_pointer_cast<ComponentType>(components[i]);
#else
			return std::static_pointer_cast<ComponentType>(components[i]);
#endif
		}
	}

	return nullptr;
}